﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace IssueIT.Core.Util
{
	public interface ICache<TKey, TValue> : IEnumerable<TValue>
	{
		int Count { get; }
		bool Contains(TKey key);
		TValue this[TKey key] { get; set; }
		void Clear();
	}

	public class Cache<TKey, TValue> : ICache<TKey, TValue>
	{
		private readonly IDictionary<TKey, TValue> _values;
		private readonly Func<TKey, TValue> _valueFactory;
		private readonly object _lock = new object();

		public Cache(Func<TKey, TValue> valueFactory) : this(new Dictionary<TKey, TValue>(), valueFactory)
		{
		}

		public Cache(IDictionary<TKey, TValue> values, Func<TKey, TValue> valueFactory)
		{
			_values = values;
			_valueFactory = valueFactory;
		}

		public int Count
		{
			get
			{
				return _values.Count;
			}
		}

		public bool Contains(TKey key)
		{
			return _values.ContainsKey(key);
		}

		public TValue this[TKey key]
		{
			get
			{
				if( _values.ContainsKey(key) )
				{
					return _values[key];
				}

				lock(_lock)
				{
					var value = _valueFactory(key);
					_values.Add(key, value);
					return value;
				}
			}
			set
			{
				_values[key] = value;
			}
		}

		public void Clear()
		{
			_values.Clear();
		}

		public IEnumerator<TValue> GetEnumerator()
		{
			return _values.Values.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}

}